#ifndef SESSION_H_
#define SESSION_H_

#include <stdint.h>
#include <uv.h>

#include "define.h"

class Worker;

enum
{
    SESSION_STATUS_INIT = 0x01,
    SESSION_STATUS_CONN = 0x01,
    SESSION_STATUS_AUTH = 0x02,
    SESSION_STATUS_CMD = 0x03,
    SESSION_STATUS_TARGET = 0x04,
    SESSION_STATUS_RELAY = 0x05,
    SESSION_STATUS_FIN = 0x06,
};

class Session
{
private:
    uint8_t m_status;
    uint32_t m_ipaddr;
    bool m_isAuthNone;
    std::string m_userName;
    std::string m_password;    
    int m_commandTimeout;
    int m_idleTimeout;
public:
    Worker *m_worker;
    uint64_t m_lastRecvTick;
    bool m_hastarget;
    char m_targetInfo[TARGET_INFO_SIZE];
    uint16_t m_targetPort;
    uv_getaddrinfo_t m_resolver;
    uint32_t m_sessionId;
    uint32_t m_cmdRecvLen;
    char m_cmdRecvBuf[CMD_BUFF_SIZE];
    char m_cmdSendBuf[CMD_BUFF_SIZE];

    uint8_t m_targetType;
    uv_timer_t m_sessionTimer;

    uv_tcp_t m_connectTcp;
    uv_tcp_t *m_targetTcp;
    uv_connect_t m_targetConn;

    uv_udp_t m_connectUdp;
    uv_udp_t m_targetUdp;
    struct sockaddr m_connectAddr;
    struct sockaddr m_targetAddr;
    struct sockaddr_storage m_ss;

    uv_buf_t m_connectBuf;
    uv_buf_t m_targetBuf;

    uint32_t m_connectRecvLen;
    uint32_t m_targetRecvLen;
    uint16_t m_udpHeaderLen;
    uint8_t m_Model;
public:
    Session() = default;
    ~Session() = default;
    bool Init(Worker *worker, uv_stream_t *pServer, uint32_t sessionId, int commandTimeout, int idleTimeout);
    void HandCommand(ssize_t nread);
    void OnSessionCheck();

    void Close(bool cache);

    void DoTcpCommand(char *cmdPos);
    void DoTcpConnectTarget(struct sockaddr *target);
    void DoTcpConnectedTarget();

    void DoUdpCommand(char *cmdPos);
    void DoUdpConnectedTarget();
    void DoUdpSendToTarget(struct sockaddr *target);

    void SendResp(char *resp, uint16_t respLen);
    void SendCMDResp(char *resp, uint8_t ver, uint8_t rep, uint8_t rsv, uint8_t atype, uint32_t addr, uint16_t port);

    void AttachTarget(uv_tcp_t *target);
};

#endif